#include "Ogre.h"

#include "EntityManager.h"
#include "EngineManager.h"

#include "OgreBulletDynamicsRigidBody.h"				 // for OgreBullet
#include "Shapes/OgreBulletCollisionsStaticPlaneShape.h" // for static planes
#include "Shapes/OgreBulletCollisionsBoxShape.h"		 // for Boxes

using namespace Ogre;

EntityManager::EntityManager(){ };
EntityManager::~EntityManager(){ };

bool EntityManager::Startup(SceneManager *sceneMgr, Vector3 &gravityVector, AxisAlignedBox &bounds)
{
	mSceneMgr = sceneMgr;

	debugDrawer = new OgreBulletCollisions::DebugDrawer();
	debugDrawer->setDrawWireframe(true);

	mWorld = new OgreBulletDynamics::DynamicsWorld(mSceneMgr, bounds, gravityVector);
	mWorld->setDebugDrawer(debugDrawer);
	mWorld->setShowDebugShapes(true);

	SceneNode *node = mSceneMgr->getRootSceneNode()->createChildSceneNode("debugDrawer", Ogre::Vector3::ZERO);
 	node->attachObject(static_cast<SimpleRenderable *>( debugDrawer ));

	// add collision detection to it
	OgreBulletCollisions::CollisionShape *Shape;
	Shape = new OgreBulletCollisions::StaticPlaneCollisionShape(Ogre::Vector3::UNIT_Y, 0); // (normal, distance)
	// a body is needed for the shape
	OgreBulletDynamics::RigidBody *defaultPlaneBody = new OgreBulletDynamics::RigidBody("BasePlane", mWorld);
	defaultPlaneBody->setStaticShape(Shape, 0.1, 0.8);// (shape, restitution, friction)
	// push the created objects to the deques
	mShapes.push_back(Shape);
	mBodies.push_back(defaultPlaneBody);
	
	return true;
}

bool EntityManager::AddEntity(Vector3 &Position, Vector3 &StartVel, EntityType type)
{
	Vector3 size = Vector3::ZERO;	// size of the box

	Entity *entity = mSceneMgr->createEntity(
			"Box" + StringConverter::toString(mNumEntitiesInstanced),
			"cube.mesh");			    
	entity->setCastShadows(true);
	// we need the bounding box of the box to be able to set the size of the Bullet-box
	AxisAlignedBox boundingB = entity->getBoundingBox();
	size = boundingB.getSize(); size /= 2.0f; // only the half needed
	size *= 0.98f;	// Bullet margin is a bit bigger so we need a smaller size
							// (Bullet 2.76 Physics SDK Manual page 18)
	entity->setMaterialName("Metal/BumpyMetal");

	SceneNode *node = mSceneMgr->getRootSceneNode()->createChildSceneNode();
	node->attachObject(entity);
	node->scale(0.05f, 0.05f, 0.05f);	// the cube is too big for us
 	size *= 0.05f;						// don't forget to scale down the Bullet-box too

	// after that create the Bullet shape with the calculated size	
	OgreBulletCollisions::CollisionShape *sceneBoxShape = new OgreBulletCollisions::BoxCollisionShape(size);
	
	// and the Bullet rigid body
	OgreBulletDynamics::RigidBody *defaultBody = new OgreBulletDynamics::RigidBody(
			"defaultBoxRigid" + StringConverter::toString(mNumEntitiesInstanced), 
			mWorld);
	defaultBody->setShape(	node,
			sceneBoxShape,
			0.6f,			// dynamic body restitution
			0.6f,			// dynamic body friction
			1.0f, 			// dynamic bodymass
			Position,		// starting position of the box
			Quaternion(0,0,0,1));// orientation of the box

	mNumEntitiesInstanced++;				

	defaultBody->setLinearVelocity( StartVel ); // shooting speed
	// push the created objects to the dequese
	mShapes.push_back(sceneBoxShape);
	mBodies.push_back(defaultBody);

	return true;
}

void EntityManager::Shutdown()
{
	std::deque<OgreBulletDynamics::RigidBody *>::iterator itBody = mBodies.begin();
	while (mBodies.end() != itBody)
	{   
		delete *itBody; 
		++itBody;
	}	
	// OgreBullet physic delete - Shapes
	std::deque<OgreBulletCollisions::CollisionShape *>::iterator itShape = mShapes.begin();
	while (mShapes.end() != itShape)
	{   
		delete *itShape; 
		++itShape;
	}
	mBodies.clear();
	mShapes.clear();
	delete mWorld->getDebugDrawer();
	mWorld->setDebugDrawer(0);
	delete mWorld;
}